home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume13 / m4 / part01 next >
Encoding:
Internet Message Format  |  1988-02-27  |  59.8 KB

  1. Subject:  v13i038:  Public domain M4 macro processor, Part01/02
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Ozan Yigit <yunexus!oz>
  7. Posting-number: Volume 13, Issue 38
  8. Archive-name: m4/part01
  9.  
  10.  
  11. #! /bin/sh
  12. # This is a shell archive, meaning:
  13. # 1. Remove everything above the #! /bin/sh line.
  14. # 2. Save the resulting text in a file.
  15. # 3. Execute the file with /bin/sh (not csh) to create the files:
  16. #    makefile
  17. #    mdef.h
  18. #    extr.h
  19. #    main.c
  20. #    eval.c
  21. #    serv.c
  22. #    look.c
  23. #    misc.c
  24. #    expr.c
  25. export PATH; PATH=/bin:$PATH
  26. echo shar: extracting "'makefile'" '(1372 characters)'
  27. if test -f 'makefile'
  28. then
  29.     echo shar: will not over-write existing file "'makefile'"
  30. else
  31. sed 's/^    X//' << \SHAR_EOF > 'makefile'
  32.     X#
  33.     X# pd m4    [oz]
  34.     X#
  35.     X#    -DEXTENDED 
  36.     X#        if you like to get paste & spaste macros.
  37.     X#    -DVOID 
  38.     X#        if your C compiler does NOT support void.
  39.     X#    -DGETOPT
  40.     X#        if you STILL do not have getopt    in your library.
  41.     X#        [This means your library is broken. Fix it.]
  42.     X#    -DDUFFCP
  43.     X#        if you do not have fast memcpy in your library.
  44.     X#
  45.     XCFLAGS = -O -DEXTENDED
  46.     XDEST =  /usr/local/bin
  47.     XMANL =     /usr/man/manl
  48.     XOBJS =  main.o eval.o serv.o look.o misc.o expr.o
  49.     XCSRC =  main.c eval.c serv.c look.c misc.c expr.c
  50.     XINCL =  mdef.h extr.h
  51.     XMSRC =  ack.m4 hanoi.m4 hash.m4 sqroot.m4 string.m4 test.m4
  52.     XDOCS =    README MANIFEST m4.1
  53.     X
  54.     XMBIN = /usr/bin
  55.     X
  56.     Xm4: ${OBJS}
  57.     X    @echo "loading m4.."
  58.     X    @cc -s -o m4 ${OBJS}
  59.     X    @size m4
  60.     X
  61.     X${OBJS}: ${INCL} 
  62.     X
  63.     Xlint:
  64.     X    lint -h ${CSRC}
  65.     X
  66.     Xinstall: m4
  67.     X    install ./m4 ${DEST}/m4
  68.     X    cp ./m4.1 ${MANL}/m4.l
  69.     X
  70.     Xdeinstall: 
  71.     X    rm -f ${DEST}/m4
  72.     X    rm -f ${MANL}/m4.l
  73.     Xtime: m4
  74.     X    @echo "timing comparisons.."
  75.     X    @echo "un*x m4:"
  76.     X    time ${MBIN}/m4 <test.m4 >unxm4.out
  77.     X    @echo "pd m4:"
  78.     X    time ./m4 <test.m4 >pdm4.out
  79.     X    @echo "un*x m4:"
  80.     X    time ${MBIN}/m4 <test.m4 >unxm4.out
  81.     X    @echo "pd m4:"
  82.     X    time ./m4 <test.m4 >pdm4.out
  83.     X    @echo "un*x m4:"
  84.     X    time ${MBIN}/m4 <test.m4 >unxm4.out
  85.     X    @echo "pd m4:"
  86.     X    time ./m4 <test.m4 >pdm4.out
  87.     X    @echo "output comparisons.."
  88.     X    -diff pdm4.out unxm4.out
  89.     X    @rm -f pdm4.out unxm4.out
  90.     Xclean:
  91.     X    rm -f *.o core m4 *.out
  92.     Xpack:
  93.     X    shar -a makefile ${INCL} ${CSRC} >M4MAIN.SHAR
  94.     X    shar -a ${MSRC} ${DOCS} >M4MSRC.SHAR
  95. SHAR_EOF
  96. if test 1372 -ne "`wc -c < 'makefile'`"
  97. then
  98.     echo shar: error transmitting "'makefile'" '(should have been 1372 characters)'
  99. fi
  100. fi # end of overwriting check
  101. echo shar: extracting "'mdef.h'" '(4711 characters)'
  102. if test -f 'mdef.h'
  103. then
  104.     echo shar: will not over-write existing file "'mdef.h'"
  105. else
  106. sed 's/^    X//' << \SHAR_EOF > 'mdef.h'
  107.     X/*
  108.     X * mdef.h
  109.     X * Facility: m4 macro processor
  110.     X * by: oz
  111.     X */
  112.     X
  113.     X
  114.     X#ifndef unix
  115.     X#define unix 0
  116.     X#endif 
  117.     X
  118.     X#ifndef vms
  119.     X#define vms 0
  120.     X#endif
  121.     X
  122.     X#if vms
  123.     X
  124.     X#include stdio
  125.     X#include ctype
  126.     X#include signal
  127.     X
  128.     X#else 
  129.     X
  130.     X#include <stdio.h>
  131.     X#include <ctype.h>
  132.     X#include <signal.h>
  133.     X
  134.     X#endif
  135.     X
  136.     X/*
  137.     X *
  138.     X * m4 constants..
  139.     X *
  140.     X */
  141.     X 
  142.     X#define MACRTYPE        1
  143.     X#define DEFITYPE        2
  144.     X#define EXPRTYPE        3
  145.     X#define SUBSTYPE        4
  146.     X#define IFELTYPE        5
  147.     X#define LENGTYPE        6
  148.     X#define CHNQTYPE        7
  149.     X#define SYSCTYPE        8
  150.     X#define UNDFTYPE        9
  151.     X#define INCLTYPE        10
  152.     X#define SINCTYPE        11
  153.     X#define PASTTYPE        12
  154.     X#define SPASTYPE        13
  155.     X#define INCRTYPE        14
  156.     X#define IFDFTYPE        15
  157.     X#define PUSDTYPE        16
  158.     X#define POPDTYPE        17
  159.     X#define SHIFTYPE        18
  160.     X#define DECRTYPE        19
  161.     X#define DIVRTYPE        20
  162.     X#define UNDVTYPE        21
  163.     X#define DIVNTYPE        22
  164.     X#define MKTMTYPE        23
  165.     X#define ERRPTYPE        24
  166.     X#define M4WRTYPE        25
  167.     X#define TRNLTYPE        26
  168.     X#define DNLNTYPE        27
  169.     X#define DUMPTYPE        28
  170.     X#define CHNCTYPE        29
  171.     X#define INDXTYPE        30
  172.     X#define SYSVTYPE        31
  173.     X#define EXITTYPE        32
  174.     X#define DEFNTYPE        33
  175.     X 
  176.     X#define STATIC          128
  177.     X
  178.     X/*
  179.     X * m4 special characters
  180.     X */
  181.     X 
  182.     X#define ARGFLAG         '$'
  183.     X#define LPAREN          '('
  184.     X#define RPAREN          ')'
  185.     X#define LQUOTE          '`'
  186.     X#define RQUOTE          '\''
  187.     X#define COMMA           ','
  188.     X#define SCOMMT          '#'
  189.     X#define ECOMMT          '\n'
  190.     X
  191.     X/*
  192.     X * definitions of diversion files. If the name of
  193.     X * the file is changed, adjust UNIQUE to point to the
  194.     X * wildcard (*) character in the filename.
  195.     X */
  196.     X
  197.     X#if unix
  198.     X#define DIVNAM  "/tmp/m4*XXXXXX"        /* unix diversion files    */
  199.     X#define UNIQUE          7               /* unique char location    */
  200.     X#else
  201.     X#if vms
  202.     X#define DIVNAM  "sys$login:m4*XXXXXX"   /* vms diversion files     */
  203.     X#define UNIQUE          12              /* unique char location    */
  204.     X#else
  205.     X#define DIVNAM    "\M4*XXXXXX"        /* msdos diversion files   */
  206.     X#define    UNIQUE        3            /* unique char location    */
  207.     X#endif
  208.     X#endif
  209.     X
  210.     X/*
  211.     X * other important constants
  212.     X */
  213.     X
  214.     X#define EOS             (char) 0
  215.     X#define MAXINP          10              /* maximum include files   */
  216.     X#define MAXOUT          10              /* maximum # of diversions */
  217.     X#define MAXSTR          512             /* maximum size of string  */
  218.     X#define BUFSIZE         4096            /* size of pushback buffer */
  219.     X#define STACKMAX        1024            /* size of call stack      */
  220.     X#define STRSPMAX        4096            /* size of string space    */
  221.     X#define MAXTOK          MAXSTR          /* maximum chars in a tokn */
  222.     X#define HASHSIZE        199             /* maximum size of hashtab */
  223.     X 
  224.     X#define ALL             1
  225.     X#define TOP             0
  226.     X 
  227.     X#define TRUE            1
  228.     X#define FALSE           0
  229.     X#define cycle           for(;;)
  230.     X
  231.     X#ifdef VOID
  232.     X#define void            int             /* define if void is void. */
  233.     X#endif
  234.     X
  235.     X/*
  236.     X * m4 data structures
  237.     X */
  238.     X 
  239.     Xtypedef struct ndblock *ndptr;
  240.     X 
  241.     Xstruct ndblock {                /* hastable structure         */
  242.     X        char    *name;          /* entry name..               */
  243.     X        char    *defn;          /* definition..               */
  244.     X        int     type;           /* type of the entry..        */
  245.     X        ndptr   nxtptr;         /* link to next entry..       */
  246.     X};
  247.     X 
  248.     X#define nil     ((ndptr) 0)
  249.     X 
  250.     Xstruct keyblk {
  251.     X        char    *knam;          /* keyword name */
  252.     X        int     ktyp;           /* keyword type */
  253.     X};
  254.     X
  255.     Xtypedef union {            /* stack structure */
  256.     X    int    sfra;        /* frame entry  */
  257.     X    char     *sstr;        /* string entry */
  258.     X} stae;
  259.     X
  260.     X/*
  261.     X * macros for readibility and/or speed
  262.     X *
  263.     X *      gpbc()  - get a possibly pushed-back character
  264.     X *      min()   - select the minimum of two elements
  265.     X *      pushf() - push a call frame entry onto stack
  266.     X *      pushs() - push a string pointer onto stack
  267.     X */
  268.     X#define gpbc()      (bp > buf) ? *--bp : getc(infile[ilevel])
  269.     X#define min(x,y) ((x > y) ? y : x)
  270.     X#define pushf(x) if (sp < STACKMAX) mstack[++sp].sfra = (x)
  271.     X#define pushs(x) if (sp < STACKMAX) mstack[++sp].sstr = (x)
  272.     X
  273.     X/*
  274.     X *        .                   .
  275.     X *    |   .    |  <-- sp        |  .  |
  276.     X *    +-------+            +-----+
  277.     X *    | arg 3 ----------------------->| str |
  278.     X *    +-------+            |  .  |
  279.     X *    | arg 2 ---PREVEP-----+        .
  280.     X *    +-------+          |
  281.     X *        .              |        |     |
  282.     X *    +-------+          |     +-----+
  283.     X *    | plev    |  PARLEV     +-------->| str |
  284.     X *    +-------+            |  .  |
  285.     X *    | type    |  CALTYP           .
  286.     X *    +-------+
  287.     X *    | prcf    ---PREVFP--+
  288.     X *    +-------+         |
  289.     X *    |   .    |  PREVSP  |
  290.     X *        .              |
  291.     X *    +-------+       |
  292.     X *    |    <----------+
  293.     X *    +-------+
  294.     X *
  295.     X */
  296.     X#define PARLEV  (mstack[fp].sfra)
  297.     X#define CALTYP  (mstack[fp-1].sfra)
  298.     X#define PREVEP    (mstack[fp+3].sstr)
  299.     X#define PREVSP    (fp-3)
  300.     X#define PREVFP    (mstack[fp-2].sfra)
  301. SHAR_EOF
  302. if test 4711 -ne "`wc -c < 'mdef.h'`"
  303. then
  304.     echo shar: error transmitting "'mdef.h'" '(should have been 4711 characters)'
  305. fi
  306. fi # end of overwriting check
  307. echo shar: extracting "'extr.h'" '(1136 characters)'
  308. if test -f 'extr.h'
  309. then
  310.     echo shar: will not over-write existing file "'extr.h'"
  311. else
  312. sed 's/^    X//' << \SHAR_EOF > 'extr.h'
  313.     Xextern ndptr hashtab[];        /* hash table for macros etc.  */
  314.     Xextern char buf[];        /* push-back buffer           */
  315.     Xextern char *bp;        /* first available character   */
  316.     Xextern char *endpbb;        /* end of push-back buffer     */
  317.     Xextern stae mstack[];        /* stack of m4 machine         */
  318.     Xextern char *ep;        /* first free char in strspace */
  319.     Xextern char *endest;        /* end of string space           */
  320.     Xint sp;             /* current m4  stack pointer   */
  321.     Xint fp;             /* m4 call frame pointer       */
  322.     Xextern FILE *infile[];        /* input file stack (0=stdin)  */
  323.     Xextern FILE *outfile[];        /* diversion array(0=bitbucket)*/
  324.     Xextern FILE *active;        /* active output file pointer  */
  325.     Xextern char *m4temp;        /* filename for diversions     */
  326.     Xextern int ilevel;        /* input file stack pointer    */
  327.     Xextern int oindex;        /* diversion index..           */
  328.     Xextern char *null;        /* as it says.. just a null..  */
  329.     Xextern char *m4wraps;        /* m4wrap string default..     */
  330.     Xextern char lquote;        /* left quote character  (`)   */
  331.     Xextern char rquote;        /* right quote character (')   */
  332.     Xextern char scommt;        /* start character for comment */
  333.     Xextern char ecommt;        /* end character for comment   */
  334. SHAR_EOF
  335. if test 1136 -ne "`wc -c < 'extr.h'`"
  336. then
  337.     echo shar: error transmitting "'extr.h'" '(should have been 1136 characters)'
  338. fi
  339. fi # end of overwriting check
  340. echo shar: extracting "'main.c'"
  341. if test -f 'main.c'
  342. then
  343.     echo shar: will not over-write existing file "'main.c'"
  344. else
  345. cat << \SHAR_EOF > 'main.c'
  346. /*
  347.  * main.c
  348.  * Facility: m4 macro processor
  349.  * by: oz
  350.  */
  351.  
  352. #include "mdef.h"
  353.  
  354. /*
  355.  * m4 - macro processor
  356.  *
  357.  * PD m4 is based on the macro tool distributed with the software 
  358.  * tools (VOS) package, and described in the "SOFTWARE TOOLS" and 
  359.  * "SOFTWARE TOOLS IN PASCAL" books. It has been expanded to include 
  360.  * most of the command set of SysV m4, the standard UN*X macro processor.
  361.  *
  362.  * Since both PD m4 and UN*X m4 are based on SOFTWARE TOOLS macro,
  363.  * there may be certain implementation similarities between
  364.  * the two. The PD m4 was produced without ANY references to m4
  365.  * sources.
  366.  *
  367.  * References:
  368.  *
  369.  *    Software Tools distribution: macro
  370.  *
  371.  *    Kernighan, Brian W. and P. J. Plauger, SOFTWARE
  372.  *    TOOLS IN PASCAL, Addison-Wesley, Mass. 1981
  373.  *
  374.  *    Kernighan, Brian W. and P. J. Plauger, SOFTWARE
  375.  *    TOOLS, Addison-Wesley, Mass. 1976
  376.  *
  377.  *    Kernighan, Brian W. and Dennis M. Ritchie,
  378.  *    THE M4 MACRO PROCESSOR, Unix Programmer's Manual,
  379.  *    Seventh Edition, Vol. 2, Bell Telephone Labs, 1979
  380.  *
  381.  *    System V man page for M4
  382.  *
  383.  * Modification History:
  384.  *
  385.  * Jan 28 1986 Oz    Break the whole thing into little
  386.  *            pieces, for easier (?) maintenance.
  387.  *
  388.  * Dec 12 1985 Oz    Optimize the code, try to squeeze
  389.  *            few microseconds out..
  390.  *
  391.  * Dec 05 1985 Oz    Add getopt interface, define (-D),
  392.  *            undefine (-U) options.
  393.  *
  394.  * Oct 21 1985 Oz    Clean up various bugs, add comment handling.
  395.  *
  396.  * June 7 1985 Oz    Add some of SysV m4 stuff (m4wrap, pushdef,
  397.  *            popdef, decr, shift etc.).
  398.  *
  399.  * June 5 1985 Oz    Initial cut.
  400.  *
  401.  * Implementation Notes:
  402.  *
  403.  * [1]    PD m4 uses a different (and simpler) stack mechanism than the one 
  404.  *    described in Software Tools and Software Tools in Pascal books. 
  405.  *    The triple stack nonsense is replaced with a single stack containing 
  406.  *    the call frames and the arguments. Each frame is back-linked to a 
  407.  *     previous stack frame, which enables us to rewind the stack after 
  408.  *     each nested call is completed. Each argument is a character pointer 
  409.  *    to the beginning of the argument string within the string space.
  410.  *    The only exceptions to this are (*) arg 0 and arg 1, which are
  411.  *     the macro definition and macro name strings, stored dynamically
  412.  *    for the hash table.
  413.  *
  414.  *        .                       .
  415.  *    |   .    |  <-- sp            |  .  |
  416.  *    +-------+                +-----+
  417.  *    | arg 3 ------------------------------->| str |
  418.  *    +-------+                |  .  |
  419.  *    | arg 2 --------------+            .
  420.  *    +-------+          |
  421.  *        *              |            |     |
  422.  *    +-------+          |         +-----+
  423.  *    | plev    |  <-- fp     +---------------->| str |
  424.  *    +-------+                |  .  |
  425.  *    | type    |                   .
  426.  *    +-------+
  427.  *    | prcf    -----------+        plev: paren level
  428.  *    +-------+         |        type: call type
  429.  *    |   .    |        |        prcf: prev. call frame
  430.  *        .              |
  431.  *    +-------+       |
  432.  *    |    <----------+
  433.  *    +-------+
  434.  *
  435.  * [2]    We have three types of null values:
  436.  *
  437.  *        nil  - nodeblock pointer type 0
  438.  *        null - null string ("")
  439.  *        NULL - Stdio-defined NULL
  440.  *
  441.  */
  442.  
  443. ndptr hashtab[HASHSIZE];    /* hash table for macros etc.  */
  444. char buf[BUFSIZE];        /* push-back buffer           */
  445. char *bp = buf;         /* first available character   */
  446. char *endpbb = buf+BUFSIZE;    /* end of push-back buffer     */
  447. stae mstack[STACKMAX+1];     /* stack of m4 machine         */
  448. char strspace[STRSPMAX+1];    /* string space for evaluation */
  449. char *ep = strspace;        /* first free char in strspace */
  450. char *endest= strspace+STRSPMAX;/* end of string space           */
  451. int sp;             /* current m4  stack pointer   */
  452. int fp;             /* m4 call frame pointer       */
  453. FILE *infile[MAXINP];        /* input file stack (0=stdin)  */
  454. FILE *outfile[MAXOUT];        /* diversion array(0=bitbucket)*/
  455. FILE *active;            /* active output file pointer  */
  456. char *m4temp;            /* filename for diversions     */
  457. int ilevel = 0;         /* input file stack pointer    */
  458. int oindex = 0;         /* diversion index..           */
  459. char *null = "";                /* as it says.. just a null..  */
  460. char *m4wraps = "";             /* m4wrap string default..     */
  461. char lquote = LQUOTE;        /* left quote character  (`)   */
  462. char rquote = RQUOTE;        /* right quote character (')   */
  463. char scommt = SCOMMT;        /* start character for comment */
  464. char ecommt = ECOMMT;        /* end character for comment   */
  465. struct keyblk keywrds[] = {    /* m4 keywords to be installed */
  466.     "include",      INCLTYPE,
  467.     "sinclude",     SINCTYPE,
  468.     "define",       DEFITYPE,
  469.     "defn",         DEFNTYPE,
  470.     "divert",       DIVRTYPE,
  471.     "expr",         EXPRTYPE,
  472.     "eval",         EXPRTYPE,
  473.     "substr",       SUBSTYPE,
  474.     "ifelse",       IFELTYPE,
  475.     "ifdef",        IFDFTYPE,
  476.     "len",          LENGTYPE,
  477.     "incr",         INCRTYPE,
  478.     "decr",         DECRTYPE,
  479.     "dnl",          DNLNTYPE,
  480.     "changequote",  CHNQTYPE,
  481.     "changecom",    CHNCTYPE,
  482.     "index",        INDXTYPE,
  483. #ifdef EXTENDED
  484.     "paste",        PASTTYPE,
  485.     "spaste",       SPASTYPE,
  486. #endif
  487.     "popdef",       POPDTYPE,
  488.     "pushdef",      PUSDTYPE,
  489.     "dumpdef",      DUMPTYPE,
  490.     "shift",        SHIFTYPE,
  491.     "translit",     TRNLTYPE,
  492.     "undefine",     UNDFTYPE,
  493.     "undivert",     UNDVTYPE,
  494.     "divnum",       DIVNTYPE,
  495.     "maketemp",     MKTMTYPE,
  496.     "errprint",     ERRPTYPE,
  497.     "m4wrap",       M4WRTYPE,
  498.     "m4exit",       EXITTYPE,
  499. #if unix || vms
  500.     "syscmd",       SYSCTYPE,
  501.     "sysval",       SYSVTYPE,
  502. #endif
  503. #if unix
  504.     "unix",         MACRTYPE,
  505. #else
  506. #if vms
  507.     "vms",          MACRTYPE,
  508. #endif
  509. #endif
  510. };
  511.  
  512. #define MAXKEYS    (sizeof(keywrds)/sizeof(struct keyblk))
  513.  
  514. extern ndptr lookup();
  515. extern ndptr addent();
  516. extern int onintr();
  517.  
  518. extern char *malloc();
  519. extern char *mktemp();
  520.  
  521. extern int optind;
  522. extern char *optarg;
  523.  
  524. main(argc,argv)
  525. char *argv[];
  526. {
  527.     register int c;
  528.     register int n;
  529.     char *p;
  530.  
  531.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  532.         signal(SIGINT, onintr);
  533. #ifdef NONZEROPAGES
  534.     initm4();
  535. #endif
  536.     initkwds();
  537.  
  538.     while ((c = getopt(argc, argv, "tD:U:o:")) != EOF)
  539.         switch(c) {
  540.  
  541.         case 'D':               /* define something..*/
  542.             for (p = optarg; *p; p++)
  543.                 if (*p == '=')
  544.                     break;
  545.             if (*p)
  546.                 *p++ = EOS;
  547.             dodefine(optarg, p);
  548.             break;
  549.         case 'U':               /* undefine...       */
  550.             remhash(optarg, TOP);
  551.             break;
  552.         case 'o':        /* specific output   */
  553.         case '?':
  554.         default:
  555.             usage();
  556.         }
  557.  
  558.     infile[0] = stdin;        /* default input (naturally) */
  559.     active = stdout;        /* default active output     */
  560.     m4temp = mktemp(DIVNAM);    /* filename for diversions   */
  561.  
  562.     sp = -1;            /* stack pointer initialized */
  563.     fp = 0;             /* frame pointer initialized */
  564.  
  565.     macro();            /* get some work done here   */
  566.  
  567.     if (*m4wraps) {         /* anything for rundown ??   */
  568.         ilevel = 0;        /* in case m4wrap includes.. */
  569.         putback(EOF);        /* eof is a must !!         */
  570.         pbstr(m4wraps);     /* user-defined wrapup act   */
  571.         macro();        /* last will and testament   */
  572.     }
  573.     else                /* default wrap-up: undivert */
  574.         for (n = 1; n < MAXOUT; n++)
  575.             if (outfile[n] != NULL)
  576.                 getdiv(n);
  577.  
  578.                     /* remove bitbucket if used  */
  579.     if (outfile[0] != NULL) {
  580.         (void) fclose(outfile[0]);
  581.         m4temp[UNIQUE] = '0';
  582. #if vms
  583.         (void) remove(m4temp);
  584. #else
  585.         (void) unlink(m4temp);
  586. #endif
  587.     }
  588.  
  589.     exit(0);
  590. }
  591.  
  592. ndptr inspect();    /* forward ... */
  593.  
  594. /*
  595.  * macro - the work horse..
  596.  *
  597.  */
  598. macro() {
  599.     char token[MAXTOK];
  600.     register char *s;
  601.     register int t, l;
  602.     register ndptr p;
  603.     register int  nlpar;
  604.  
  605.     cycle {
  606.         if ((t = gpbc()) == '_' || isalpha(t)) {
  607.             putback(t);
  608.             if ((p = inspect(s = token)) == nil) {
  609.                 if (sp < 0)
  610.                     while (*s)
  611.                         putc(*s++, active);
  612.                 else
  613.                     while (*s)
  614.                         chrsave(*s++);
  615.             }
  616.             else {
  617.         /*
  618.          * real thing.. First build a call frame:
  619.          *
  620.          */
  621.                 pushf(fp);    /* previous call frm */
  622.                 pushf(p->type); /* type of the call  */
  623.                 pushf(0);    /* parenthesis level */
  624.                 fp = sp;    /* new frame pointer */
  625.         /*
  626.          * now push the string arguments:
  627.          *
  628.          */
  629.                 pushs(p->defn);          /* defn string */
  630.                 pushs(p->name);          /* macro name  */
  631.                 pushs(ep);          /* start next..*/
  632.  
  633.                 putback(l = gpbc());
  634.                 if (l != LPAREN)  {   /* add bracks  */
  635.                     putback(RPAREN);
  636.                     putback(LPAREN);
  637.                 }
  638.             }
  639.         }
  640.         else if (t == EOF) {
  641.             if (sp > -1)
  642.                 error("m4: unexpected end of input");
  643.             if (--ilevel < 0)
  644.                 break;            /* all done thanks.. */
  645.             (void) fclose(infile[ilevel+1]);
  646.             continue;
  647.         }
  648.     /*
  649.      * non-alpha single-char token seen..
  650.      * [the order of else if .. stmts is
  651.      * important.]
  652.      *
  653.      */
  654.         else if (t == lquote) {         /* strip quotes */
  655.             nlpar = 1;
  656.             do {
  657.                 if ((l = gpbc()) == rquote)
  658.                     nlpar--;
  659.                 else if (l == lquote)
  660.                     nlpar++;
  661.                 else if (l == EOF)
  662.                     error("m4: missing right quote");
  663.                 if (nlpar > 0)
  664.                     chrsave(l);
  665.             }
  666.             while (nlpar != 0);
  667.         }
  668.  
  669.         else if (sp < 0) {        /* not in a macro at all */
  670.             if (t == scommt) {    /* comment handling here */
  671.                 putc(t, active);
  672.                 while ((t = gpbc()) != ecommt)
  673.                     putc(t, active);
  674.             }
  675.             putc(t, active);    /* output directly..     */
  676.         }
  677.  
  678.         else switch(t) {
  679.  
  680.         case LPAREN:
  681.             if (PARLEV > 0)
  682.                 chrsave(t);
  683.             while (isspace(l = gpbc()))
  684.                 ;        /* skip blank, tab, nl.. */
  685.             putback(l);
  686.             PARLEV++;
  687.             break;
  688.  
  689.         case RPAREN:
  690.             if (--PARLEV > 0)
  691.                 chrsave(t);
  692.             else {            /* end of argument list */
  693.                 chrsave(EOS);
  694.  
  695.                 if (sp == STACKMAX)
  696.                     error("m4: internal stack overflow");
  697.  
  698.                 if (CALTYP == MACRTYPE)
  699.                     expand(mstack+fp+1, sp-fp);
  700.                 else
  701.                     eval(mstack+fp+1, sp-fp, CALTYP);
  702.  
  703.                 ep = PREVEP;    /* flush strspace */
  704.                 sp = PREVSP;    /* previous sp..  */
  705.                 fp = PREVFP;    /* rewind stack...*/
  706.             }
  707.             break;
  708.  
  709.         case COMMA:
  710.             if (PARLEV == 1)    {
  711.                 chrsave(EOS);        /* new argument   */
  712.                 while (isspace(l = gpbc()))
  713.                     ;
  714.                 putback(l);
  715.                 pushs(ep);
  716.             }
  717.             break;
  718.         default:
  719.             chrsave(t);            /* stack the char */
  720.             break;
  721.         }
  722.     }
  723. }
  724.  
  725.  
  726. /*
  727.  * build an input token..
  728.  * consider only those starting with _ or A-Za-z. This is a
  729.  * combo with lookup to speed things up.
  730.  */
  731. ndptr
  732. inspect(tp) 
  733. register char *tp;
  734. {
  735.     register int h = 0;
  736.     register char c;
  737.     register char *name = tp;
  738.     register char *etp = tp+MAXTOK;
  739.     register ndptr p;
  740.  
  741.     while (tp < etp && (isalnum(c = gpbc()) || c == '_'))
  742.         h += (*tp++ = c);
  743.     putback(c);
  744.     if (tp == etp)
  745.         error("m4: token too long");
  746.     *tp = EOS;
  747.     for (p = hashtab[h%HASHSIZE]; p != nil; p = p->nxtptr)
  748.         if (strcmp(name, p->name) == 0)
  749.             break;
  750.     return(p);
  751. }
  752.  
  753. #ifdef NONZEROPAGES
  754. /*
  755.  * initm4 - initialize various tables. Useful only if your system 
  756.  * does not know anything about demand-zero pages.
  757.  *
  758.  */
  759. initm4()
  760. {
  761.     register int i;
  762.  
  763.     for (i = 0; i < HASHSIZE; i++)
  764.         hashtab[i] = nil;
  765.     for (i = 0; i < MAXOUT; i++)
  766.         outfile[i] = NULL;
  767. }
  768. #endif
  769.  
  770. /*
  771.  * initkwds - initialise m4 keywords as fast as possible. 
  772.  * This very similar to install, but without certain overheads,
  773.  * such as calling lookup. Malloc is not used for storing the 
  774.  * keyword strings, since we simply use the static  pointers
  775.  * within keywrds block. We also assume that there is enough memory 
  776.  * to at least install the keywords (i.e. malloc won't fail).
  777.  *
  778.  */
  779. initkwds() {
  780.     register int i;
  781.     register int h;
  782.     register ndptr p;
  783.  
  784.     for (i = 0; i < MAXKEYS; i++) {
  785.         h = hash(keywrds[i].knam);
  786.         p = (ndptr) malloc(sizeof(struct ndblock));
  787.         p->nxtptr = hashtab[h];
  788.         hashtab[h] = p;
  789.         p->name = keywrds[i].knam;
  790.         p->defn = null;
  791.         p->type = keywrds[i].ktyp | STATIC;
  792.     }
  793. }
  794. SHAR_EOF
  795. fi # end of overwriting check
  796. echo shar: extracting "'eval.c'" '(5707 characters)'
  797. if test -f 'eval.c'
  798. then
  799.     echo shar: will not over-write existing file "'eval.c'"
  800. else
  801. sed 's/^    X//' << \SHAR_EOF > 'eval.c'
  802.     X/*
  803.     X * eval.c
  804.     X * Facility: m4 macro processor
  805.     X * by: oz
  806.     X */
  807.     X
  808.     X#include "mdef.h"
  809.     X#include "extr.h"
  810.     X
  811.     Xextern ndptr lookup();
  812.     Xextern char *strsave();
  813.     Xextern char *mktemp();
  814.     X
  815.     X/*
  816.     X * eval - evaluate built-in macros.
  817.     X *      argc - number of elements in argv.
  818.     X *      argv - element vector :
  819.     X *            argv[0] = definition of a user
  820.     X *                  macro or nil if built-in.
  821.     X *            argv[1] = name of the macro or
  822.     X *                  built-in.
  823.     X *            argv[2] = parameters to user-defined
  824.     X *               .      macro or built-in.
  825.     X *               .
  826.     X *
  827.     X * Note that the minimum value for argc is 3. A call in the form
  828.     X * of macro-or-builtin() will result in:
  829.     X *            argv[0] = nullstr
  830.     X *            argv[1] = macro-or-builtin
  831.     X *            argv[2] = nullstr
  832.     X *
  833.     X */
  834.     X
  835.     Xeval (argv, argc, td)
  836.     Xregister char *argv[];
  837.     Xregister int argc;
  838.     Xregister int  td;
  839.     X{
  840.     X    register int c, n;
  841.     X    static int sysval;
  842.     X
  843.     X#ifdef DEBUG
  844.     X    printf("argc = %d\n", argc);
  845.     X    for (n = 0; n < argc; n++)
  846.     X        printf("argv[%d] = %s\n", n, argv[n]);
  847.     X#endif
  848.     X    /*
  849.     X     * if argc == 3 and argv[2] is null,
  850.     X     * then we have macro-or-builtin() type call.
  851.     X     * We adjust argc to avoid further checking..
  852.     X     *
  853.     X     */
  854.     X    if (argc == 3 && !*(argv[2]))
  855.     X        argc--;
  856.     X
  857.     X    switch (td & ~STATIC) {
  858.     X
  859.     X    case DEFITYPE:
  860.     X        if (argc > 2)
  861.     X            dodefine(argv[2], (argc > 3) ? argv[3] : null);
  862.     X        break;
  863.     X
  864.     X    case PUSDTYPE:
  865.     X        if (argc > 2)
  866.     X            dopushdef(argv[2], (argc > 3) ? argv[3] : null);
  867.     X        break;
  868.     X
  869.     X    case DUMPTYPE:
  870.     X        dodump(argv, argc);
  871.     X        break;
  872.     X
  873.     X    case EXPRTYPE:
  874.     X        /*
  875.     X         * doexpr - evaluate arithmetic expression
  876.     X         *
  877.     X         */
  878.     X        if (argc > 2)
  879.     X            pbnum(expr(argv[2]));
  880.     X        break;
  881.     X
  882.     X    case IFELTYPE:
  883.     X        if (argc > 4)
  884.     X            doifelse(argv, argc);
  885.     X        break;
  886.     X
  887.     X    case IFDFTYPE:
  888.     X        /*
  889.     X         * doifdef - select one of two alternatives based
  890.     X         *         on the existence of another definition
  891.     X         */
  892.     X        if (argc > 3) {
  893.     X            if (lookup(argv[2]) != nil)
  894.     X                pbstr(argv[3]);
  895.     X            else if (argc > 4)
  896.     X                pbstr(argv[4]);
  897.     X        }
  898.     X        break;
  899.     X
  900.     X    case LENGTYPE:
  901.     X        /*
  902.     X         * dolen - find the length of the argument
  903.     X         *
  904.     X         */
  905.     X        if (argc > 2)
  906.     X            pbnum((argc > 2) ? strlen(argv[2]) : 0);
  907.     X        break;
  908.     X
  909.     X    case INCRTYPE:
  910.     X        /*
  911.     X         * doincr - increment the value of the argument
  912.     X         *
  913.     X         */
  914.     X        if (argc > 2)
  915.     X            pbnum(atoi(argv[2]) + 1);
  916.     X        break;
  917.     X
  918.     X    case DECRTYPE:
  919.     X        /*
  920.     X         * dodecr - decrement the value of the argument
  921.     X         *
  922.     X         */
  923.     X        if (argc > 2)
  924.     X            pbnum(atoi(argv[2]) - 1);
  925.     X        break;
  926.     X
  927.     X#if unix || vms
  928.     X
  929.     X    case SYSCTYPE:
  930.     X        /*
  931.     X         * dosys - execute system command
  932.     X         *
  933.     X         */
  934.     X        if (argc > 2)
  935.     X            sysval = system(argv[2]);
  936.     X        break;
  937.     X
  938.     X    case SYSVTYPE:
  939.     X        /*
  940.     X         * dosysval - return value of the last system call.
  941.     X         *
  942.     X         */
  943.     X        pbnum(sysval);
  944.     X        break;
  945.     X#endif
  946.     X
  947.     X    case INCLTYPE:
  948.     X        if (argc > 2)
  949.     X            if (!doincl(argv[2])) {
  950.     X                fprintf(stderr,"m4: %s: ",argv[2]);
  951.     X                error("cannot open for read.");
  952.     X            }
  953.     X        break;
  954.     X
  955.     X    case SINCTYPE:
  956.     X        if (argc > 2)
  957.     X            (void) doincl(argv[2]);
  958.     X        break;
  959.     X#ifdef EXTENDED
  960.     X    case PASTTYPE:
  961.     X        if (argc > 2)
  962.     X            if (!dopaste(argv[2])) {
  963.     X                fprintf(stderr,"m4: %s: ",argv[2]);
  964.     X                error("cannot open for read.");
  965.     X            }
  966.     X        break;
  967.     X
  968.     X    case SPASTYPE:
  969.     X        if (argc > 2)
  970.     X            (void) dopaste(argv[2]);
  971.     X        break;
  972.     X#endif
  973.     X    case CHNQTYPE:
  974.     X        dochq(argv, argc);
  975.     X        break;
  976.     X
  977.     X    case CHNCTYPE:
  978.     X        dochc(argv, argc);
  979.     X        break;
  980.     X
  981.     X    case SUBSTYPE:
  982.     X        /*
  983.     X         * dosub - select substring
  984.     X         *
  985.     X         */
  986.     X        if (argc > 3)
  987.     X            dosub(argv,argc);
  988.     X        break;
  989.     X
  990.     X    case SHIFTYPE:
  991.     X        /*
  992.     X         * doshift - push back all arguments except the
  993.     X         *         first one (i.e. skip argv[2])
  994.     X         */
  995.     X        if (argc > 3) {
  996.     X            for (n = argc-1; n > 3; n--) {
  997.     X                putback(rquote);
  998.     X                pbstr(argv[n]);
  999.     X                putback(lquote);
  1000.     X                putback(',');
  1001.     X            }
  1002.     X            putback(rquote);
  1003.     X            pbstr(argv[3]);
  1004.     X            putback(lquote);
  1005.     X        }
  1006.     X        break;
  1007.     X
  1008.     X    case DIVRTYPE:
  1009.     X        if (argc > 2 && (n = atoi(argv[2])) != 0)
  1010.     X            dodiv(n);
  1011.     X        else {
  1012.     X            active = stdout;
  1013.     X            oindex = 0;
  1014.     X        }
  1015.     X        break;
  1016.     X
  1017.     X    case UNDVTYPE:
  1018.     X        doundiv(argv, argc);
  1019.     X        break;
  1020.     X
  1021.     X    case DIVNTYPE:
  1022.     X        /*
  1023.     X         * dodivnum - return the number of current
  1024.     X         * output diversion
  1025.     X         *
  1026.     X         */
  1027.     X        pbnum(oindex);
  1028.     X        break;
  1029.     X
  1030.     X    case UNDFTYPE:
  1031.     X        /*
  1032.     X         * doundefine - undefine a previously defined
  1033.     X         *        macro(s) or m4 keyword(s).
  1034.     X         */
  1035.     X        if (argc > 2)
  1036.     X            for (n = 2; n < argc; n++)
  1037.     X                remhash(argv[n], ALL);
  1038.     X        break;
  1039.     X
  1040.     X    case POPDTYPE:
  1041.     X        /*
  1042.     X         * dopopdef - remove the topmost definitions of
  1043.     X         *          macro(s) or m4 keyword(s).
  1044.     X         */
  1045.     X        if (argc > 2)
  1046.     X            for (n = 2; n < argc; n++)
  1047.     X                remhash(argv[n], TOP);
  1048.     X        break;
  1049.     X
  1050.     X    case MKTMTYPE:
  1051.     X        /*
  1052.     X         * dotemp - create a temporary file
  1053.     X         *
  1054.     X         */
  1055.     X        if (argc > 2)
  1056.     X            pbstr(mktemp(argv[2]));
  1057.     X        break;
  1058.     X
  1059.     X    case TRNLTYPE:
  1060.     X        /*
  1061.     X         * dotranslit - replace all characters in the
  1062.     X         *        source string that appears in
  1063.     X         *        the "from" string with the corresponding
  1064.     X         *        characters in the "to" string.
  1065.     X         *
  1066.     X         */
  1067.     X        if (argc > 3) {
  1068.     X            char temp[MAXTOK];
  1069.     X            if (argc > 4)
  1070.     X                map(temp, argv[2], argv[3], argv[4]);
  1071.     X            else
  1072.     X                map(temp, argv[2], argv[3], null);
  1073.     X            pbstr(temp);
  1074.     X        }
  1075.     X        else
  1076.     X            if (argc > 2)
  1077.     X            pbstr(argv[2]);
  1078.     X        break;
  1079.     X
  1080.     X    case INDXTYPE:
  1081.     X        /*
  1082.     X         * doindex - find the index of the second argument
  1083.     X         *         string in the first argument string.
  1084.     X         *         -1 if not present.
  1085.     X         */
  1086.     X        pbnum((argc > 3) ? indx(argv[2], argv[3]) : -1);
  1087.     X        break;
  1088.     X
  1089.     X    case ERRPTYPE:
  1090.     X        /*
  1091.     X         * doerrp - print the arguments to stderr file
  1092.     X         *
  1093.     X         */
  1094.     X        if (argc > 2) {
  1095.     X            for (n = 2; n < argc; n++)
  1096.     X                fprintf(stderr,"%s ", argv[n]);
  1097.     X            fprintf(stderr, "\n");
  1098.     X        }
  1099.     X        break;
  1100.     X
  1101.     X    case DNLNTYPE:
  1102.     X        /*
  1103.     X         * dodnl - eat-up-to and including newline
  1104.     X         *
  1105.     X         */
  1106.     X        while ((c = gpbc()) != '\n' && c != EOF)
  1107.     X            ;
  1108.     X        break;
  1109.     X
  1110.     X    case M4WRTYPE:
  1111.     X        /*
  1112.     X         * dom4wrap - set up for wrap-up/wind-down activity
  1113.     X         *
  1114.     X         */
  1115.     X        m4wraps = (argc > 2) ? strsave(argv[2]) : null;
  1116.     X        break;
  1117.     X
  1118.     X    case EXITTYPE:
  1119.     X        /*
  1120.     X         * doexit - immediate exit from m4.
  1121.     X         *
  1122.     X         */
  1123.     X        exit((argc > 2) ? atoi(argv[2]) : 0);
  1124.     X        break;
  1125.     X
  1126.     X    case DEFNTYPE:
  1127.     X        if (argc > 2)
  1128.     X            for (n = 2; n < argc; n++)
  1129.     X                dodefn(argv[n]);
  1130.     X        break;
  1131.     X
  1132.     X    default:
  1133.     X        error("m4: major botch in eval.");
  1134.     X        break;
  1135.     X    }
  1136.     X}
  1137. SHAR_EOF
  1138. if test 5707 -ne "`wc -c < 'eval.c'`"
  1139. then
  1140.     echo shar: error transmitting "'eval.c'" '(should have been 5707 characters)'
  1141. fi
  1142. fi # end of overwriting check
  1143. echo shar: extracting "'serv.c'" '(11554 characters)'
  1144. if test -f 'serv.c'
  1145. then
  1146.     echo shar: will not over-write existing file "'serv.c'"
  1147. else
  1148. sed 's/^    X//' << \SHAR_EOF > 'serv.c'
  1149.     X/*
  1150.     X * serv.c
  1151.     X * Facility: m4 macro processor
  1152.     X * by: oz
  1153.     X */
  1154.     X 
  1155.     X#include "mdef.h"
  1156.     X#include "extr.h" 
  1157.     X
  1158.     Xextern ndptr lookup();
  1159.     Xextern ndptr addent();
  1160.     Xextern char  *strsave();
  1161.     X 
  1162.     Xchar *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef   */
  1163.     X 
  1164.     X/*
  1165.     X * expand - user-defined macro expansion
  1166.     X *
  1167.     X */
  1168.     Xexpand(argv, argc)
  1169.     Xregister char *argv[];
  1170.     Xregister int argc;
  1171.     X{
  1172.     X        register char *t;
  1173.     X        register char *p;
  1174.     X        register int  n;
  1175.     X        register int  argno;
  1176.     X 
  1177.     X        t = argv[0];    /* defn string as a whole */
  1178.     X        p = t;
  1179.     X        while (*p)
  1180.     X                p++;
  1181.     X        p--;            /* last character of defn */
  1182.     X        while (p > t) {
  1183.     X                if (*(p-1) != ARGFLAG)
  1184.     X                        putback(*p);
  1185.     X                else {
  1186.     X                        switch (*p) {
  1187.     X 
  1188.     X                        case '#':
  1189.     X                                pbnum(argc-2);
  1190.     X                                break;
  1191.     X                        case '0':
  1192.     X                        case '1':
  1193.     X                        case '2':
  1194.     X                        case '3':
  1195.     X                        case '4':
  1196.     X                        case '5':
  1197.     X                        case '6':
  1198.     X                        case '7':
  1199.     X                        case '8':
  1200.     X                        case '9':
  1201.     X                                if ((argno = *p - '0') < argc-1)
  1202.     X                                        pbstr(argv[argno+1]);
  1203.     X                                break;
  1204.     X                        case '*':
  1205.     X                                for (n = argc - 1; n > 2; n--) {
  1206.     X                                        pbstr(argv[n]);
  1207.     X                                        putback(',');
  1208.     X                                }
  1209.     X                                pbstr(argv[2]);
  1210.     X                                break;
  1211.     X                        default :
  1212.     X                                putback(*p);
  1213.     X                                break;
  1214.     X                        }
  1215.     X                        p--;
  1216.     X                }
  1217.     X                p--;
  1218.     X        }
  1219.     X        if (p == t)         /* do last character */
  1220.     X                putback(*p);
  1221.     X}
  1222.     X 
  1223.     X/*
  1224.     X * dodefine - install definition in the table
  1225.     X *
  1226.     X */
  1227.     Xdodefine(name, defn)
  1228.     Xregister char *name;
  1229.     Xregister char *defn;
  1230.     X{
  1231.     X        register ndptr p;
  1232.     X 
  1233.     X        if (!*name)
  1234.     X                error("m4: null definition.");
  1235.     X        if (strcmp(name, defn) == 0)
  1236.     X                error("m4: recursive definition.");
  1237.     X        if ((p = lookup(name)) == nil)
  1238.     X                p = addent(name);
  1239.     X        else if (p->defn != null)
  1240.     X                free(p->defn);
  1241.     X        if (!*defn)
  1242.     X                p->defn = null;
  1243.     X        else
  1244.     X                p->defn = strsave(defn);
  1245.     X        p->type = MACRTYPE;
  1246.     X}
  1247.     X 
  1248.     X/*
  1249.     X * dodefn - push back a quoted definition of
  1250.     X *      the given name.
  1251.     X */
  1252.     X 
  1253.     Xdodefn(name)
  1254.     Xchar *name;
  1255.     X{
  1256.     X        register ndptr p;
  1257.     X 
  1258.     X        if ((p = lookup(name)) != nil && p->defn != null) {
  1259.     X                putback(rquote);
  1260.     X                pbstr(p->defn);
  1261.     X                putback(lquote);
  1262.     X        }
  1263.     X}
  1264.     X     
  1265.     X/*
  1266.     X * dopushdef - install a definition in the hash table
  1267.     X *      without removing a previous definition. Since
  1268.     X *      each new entry is entered in *front* of the
  1269.     X *      hash bucket, it hides a previous definition from
  1270.     X *      lookup.
  1271.     X */
  1272.     Xdopushdef(name, defn)
  1273.     Xregister char *name;
  1274.     Xregister char *defn;
  1275.     X{
  1276.     X        register ndptr p;
  1277.     X 
  1278.     X        if (!*name)
  1279.     X                error("m4: null definition");
  1280.     X        if (strcmp(name, defn) == 0)
  1281.     X                error("m4: recursive definition.");
  1282.     X        p = addent(name);
  1283.     X        if (!*defn)
  1284.     X                p->defn = null;
  1285.     X        else
  1286.     X                p->defn = strsave(defn);
  1287.     X        p->type = MACRTYPE;
  1288.     X}
  1289.     X 
  1290.     X/*
  1291.     X * dodumpdef - dump the specified definitions in the hash
  1292.     X *      table to stderr. If nothing is specified, the entire
  1293.     X *      hash table is dumped.
  1294.     X *
  1295.     X */
  1296.     Xdodump(argv, argc)
  1297.     Xregister char *argv[];
  1298.     Xregister int argc;
  1299.     X{
  1300.     X        register int n;
  1301.     X        ndptr p;
  1302.     X 
  1303.     X        if (argc > 2) {
  1304.     X                for (n = 2; n < argc; n++)
  1305.     X                        if ((p = lookup(argv[n])) != nil)
  1306.     X                                fprintf(stderr, dumpfmt, p->name,
  1307.     X                                p->defn);
  1308.     X        }
  1309.     X        else {
  1310.     X                for (n = 0; n < HASHSIZE; n++)
  1311.     X                        for (p = hashtab[n]; p != nil; p = p->nxtptr)
  1312.     X                                fprintf(stderr, dumpfmt, p->name,
  1313.     X                                p->defn);
  1314.     X        }
  1315.     X}
  1316.     X 
  1317.     X/*
  1318.     X * doifelse - select one of two alternatives - loop.
  1319.     X *
  1320.     X */
  1321.     Xdoifelse(argv,argc)
  1322.     Xregister char *argv[];
  1323.     Xregister int argc;
  1324.     X{
  1325.     X        cycle {
  1326.     X                if (strcmp(argv[2], argv[3]) == 0)
  1327.     X                        pbstr(argv[4]);
  1328.     X                else if (argc == 6)
  1329.     X                        pbstr(argv[5]);
  1330.     X                else if (argc > 6) {
  1331.     X                        argv += 3;
  1332.     X                        argc -= 3;
  1333.     X                        continue;
  1334.     X                }
  1335.     X                break;
  1336.     X        }
  1337.     X}
  1338.     X 
  1339.     X/*
  1340.     X * doinclude - include a given file.
  1341.     X *
  1342.     X */
  1343.     Xdoincl(ifile)
  1344.     Xchar *ifile;
  1345.     X{
  1346.     X        if (ilevel+1 == MAXINP)
  1347.     X                error("m4: too many include files.");
  1348.     X        if ((infile[ilevel+1] = fopen(ifile, "r")) != NULL) {
  1349.     X                ilevel++;
  1350.     X                return (1);
  1351.     X        }
  1352.     X        else
  1353.     X                return (0);
  1354.     X}
  1355.     X 
  1356.     X#ifdef EXTENDED
  1357.     X/*
  1358.     X * dopaste - include a given file without any
  1359.     X *           macro processing.
  1360.     X */
  1361.     Xdopaste(pfile)
  1362.     Xchar *pfile;
  1363.     X{
  1364.     X        FILE *pf;
  1365.     X        register int c;
  1366.     X 
  1367.     X        if ((pf = fopen(pfile, "r")) != NULL) {
  1368.     X                while((c = getc(pf)) != EOF)
  1369.     X                        putc(c, active);
  1370.     X                (void) fclose(pf);
  1371.     X                return(1);
  1372.     X        }
  1373.     X        else
  1374.     X                return(0);
  1375.     X}
  1376.     X#endif
  1377.     X 
  1378.     X/*
  1379.     X * dochq - change quote characters
  1380.     X *
  1381.     X */
  1382.     Xdochq(argv, argc)
  1383.     Xregister char *argv[];
  1384.     Xregister int argc;
  1385.     X{
  1386.     X        if (argc > 2) {
  1387.     X                if (*argv[2])
  1388.     X                        lquote = *argv[2];
  1389.     X                if (argc > 3) {
  1390.     X                        if (*argv[3])
  1391.     X                                rquote = *argv[3];
  1392.     X                }
  1393.     X                else
  1394.     X                        rquote = lquote;
  1395.     X        }
  1396.     X        else {
  1397.     X                lquote = LQUOTE;
  1398.     X                rquote = RQUOTE;
  1399.     X        }
  1400.     X}
  1401.     X 
  1402.     X/*
  1403.     X * dochc - change comment characters
  1404.     X *
  1405.     X */
  1406.     Xdochc(argv, argc)
  1407.     Xregister char *argv[];
  1408.     Xregister int argc;
  1409.     X{
  1410.     X        if (argc > 2) {
  1411.     X                if (*argv[2])
  1412.     X                        scommt = *argv[2];
  1413.     X                if (argc > 3) {
  1414.     X                        if (*argv[3])
  1415.     X                                ecommt = *argv[3];
  1416.     X                }
  1417.     X                else
  1418.     X                        ecommt = ECOMMT;
  1419.     X        }
  1420.     X        else {
  1421.     X                scommt = SCOMMT;
  1422.     X                ecommt = ECOMMT;
  1423.     X        }
  1424.     X}
  1425.     X 
  1426.     X/*
  1427.     X * dodivert - divert the output to a temporary file
  1428.     X *
  1429.     X */
  1430.     Xdodiv(n)
  1431.     Xregister int n;
  1432.     X{
  1433.     X        if (n < 0 || n >= MAXOUT)
  1434.     X                n = 0;                  /* bitbucket */
  1435.     X        if (outfile[n] == NULL) {
  1436.     X                m4temp[UNIQUE] = n + '0';
  1437.     X                if ((outfile[n] = fopen(m4temp, "w")) == NULL)
  1438.     X                        error("m4: cannot divert.");
  1439.     X        }
  1440.     X        oindex = n;
  1441.     X        active = outfile[n];
  1442.     X}
  1443.     X 
  1444.     X/*
  1445.     X * doundivert - undivert a specified output, or all
  1446.     X *              other outputs, in numerical order.
  1447.     X */
  1448.     Xdoundiv(argv, argc)
  1449.     Xregister char *argv[];
  1450.     Xregister int argc;
  1451.     X{
  1452.     X        register int ind;
  1453.     X        register int n;
  1454.     X 
  1455.     X        if (argc > 2) {
  1456.     X                for (ind = 2; ind < argc; ind++) {
  1457.     X                        n = atoi(argv[ind]);
  1458.     X                        if (n > 0 && n < MAXOUT && outfile[n] != NULL)
  1459.     X                                getdiv(n);
  1460.     X 
  1461.     X                }
  1462.     X        }
  1463.     X        else
  1464.     X                for (n = 1; n < MAXOUT; n++)
  1465.     X                        if (outfile[n] != NULL)
  1466.     X                                getdiv(n);
  1467.     X}
  1468.     X 
  1469.     X/*
  1470.     X * dosub - select substring
  1471.     X *
  1472.     X */
  1473.     Xdosub (argv, argc)
  1474.     Xregister char *argv[];
  1475.     Xregister int  argc;
  1476.     X{
  1477.     X        register char *ap, *fc, *k;
  1478.     X        register int nc;
  1479.     X 
  1480.     X        if (argc < 5)
  1481.     X                nc = MAXTOK;
  1482.     X        else
  1483.     X#ifdef EXPR
  1484.     X                nc = expr(argv[4]);
  1485.     X#else
  1486.     X        nc = atoi(argv[4]);
  1487.     X#endif
  1488.     X        ap = argv[2];                   /* target string */
  1489.     X#ifdef EXPR
  1490.     X        fc = ap + expr(argv[3]);        /* first char */
  1491.     X#else
  1492.     X        fc = ap + atoi(argv[3]);        /* first char */
  1493.     X#endif
  1494.     X        if (fc >= ap && fc < ap+strlen(ap))
  1495.     X                for (k = fc+min(nc,strlen(fc))-1; k >= fc; k--)
  1496.     X                        putback(*k);
  1497.     X}
  1498.     X 
  1499.     X/*
  1500.     X * map:
  1501.     X * map every character of s1 that is specified in from
  1502.     X * into s3 and replace in s. (source s1 remains untouched)
  1503.     X *
  1504.     X * This is a standard implementation of map(s,from,to) function of ICON 
  1505.     X * language. Within mapvec, we replace every character of "from" with 
  1506.     X * the corresponding character in "to". If "to" is shorter than "from", 
  1507.     X * than the corresponding entries are null, which means that those 
  1508.     X * characters dissapear altogether. Furthermore, imagine 
  1509.     X * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 
  1510.     X * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 
  1511.     X * ultimately maps to `*'. In order to achieve this effect in an efficient 
  1512.     X * manner (i.e. without multiple passes over the destination string), we 
  1513.     X * loop over mapvec, starting with the initial source character. if the 
  1514.     X * character value (dch) in this location is different than the source 
  1515.     X * character (sch), sch becomes dch, once again to index into mapvec, until 
  1516.     X * the character value stabilizes (i.e. sch = dch, in other words 
  1517.     X * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 
  1518.     X * character, it will stabilize, since mapvec[0] == 0 at all times. At the 
  1519.     X * end, we restore mapvec* back to normal where mapvec[n] == n for 
  1520.     X * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 
  1521.     X * about 5 times faster than any algorithm that makes multiple passes over 
  1522.     X * destination string.
  1523.     X *
  1524.     X */
  1525.     X     
  1526.     Xmap(dest,src,from,to)
  1527.     Xregister char *dest;
  1528.     Xregister char *src;
  1529.     Xregister char *from;
  1530.     Xregister char *to;
  1531.     X{
  1532.     X        register char *tmp;
  1533.     X        register char sch, dch;
  1534.     X        static char mapvec[128] = {
  1535.     X                0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
  1536.     X                12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
  1537.     X                24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
  1538.     X                36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
  1539.     X                48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
  1540.     X                60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
  1541.     X                72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
  1542.     X                84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
  1543.     X                96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
  1544.     X                108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
  1545.     X                120, 121, 122, 123, 124, 125, 126, 127
  1546.     X        };
  1547.     X 
  1548.     X        if (*src) {
  1549.     X                tmp = from;
  1550.     X    /*
  1551.     X     * create a mapping between "from" and "to"
  1552.     X     */
  1553.     X                while (*from)
  1554.     X                        mapvec[*from++] = (*to) ? *to++ : (char) 0;
  1555.     X     
  1556.     X                while (*src) {
  1557.     X                        sch = *src++;
  1558.     X                        dch = mapvec[sch];
  1559.     X                        while (dch != sch) {
  1560.     X                                sch = dch;
  1561.     X                                dch = mapvec[sch];
  1562.     X                        }
  1563.     X                        if (*dest = dch)
  1564.     X                                dest++;
  1565.     X                }
  1566.     X    /*
  1567.     X     * restore all the changed characters
  1568.     X     */
  1569.     X                while (*tmp) {
  1570.     X                        mapvec[*tmp] = *tmp;
  1571.     X                        tmp++;
  1572.     X                }
  1573.     X        }
  1574.     X        *dest = (char) 0;
  1575.     X}
  1576. SHAR_EOF
  1577. if test 11554 -ne "`wc -c < 'serv.c'`"
  1578. then
  1579.     echo shar: error transmitting "'serv.c'" '(should have been 11554 characters)'
  1580. fi
  1581. fi # end of overwriting check
  1582. echo shar: extracting "'look.c'" '(1617 characters)'
  1583. if test -f 'look.c'
  1584. then
  1585.     echo shar: will not over-write existing file "'look.c'"
  1586. else
  1587. sed 's/^    X//' << \SHAR_EOF > 'look.c'
  1588.     X/*
  1589.     X * look.c
  1590.     X * Facility: m4 macro processor
  1591.     X * by: oz
  1592.     X */
  1593.     X
  1594.     X#include "mdef.h"
  1595.     X#include "extr.h"
  1596.     X
  1597.     Xextern char *strsave();
  1598.     X
  1599.     X/*
  1600.     X *  hash - compute hash value using the proverbial
  1601.     X *       hashing function. Taken from K&R.
  1602.     X */
  1603.     Xhash (name)
  1604.     Xregister char *name;
  1605.     X{
  1606.     X    register int h = 0;
  1607.     X    while (*name)
  1608.     X        h += *name++;
  1609.     X    return (h % HASHSIZE);
  1610.     X}
  1611.     X
  1612.     X/*
  1613.     X * lookup - find name in the hash table
  1614.     X *
  1615.     X */
  1616.     Xndptr lookup(name)
  1617.     Xchar *name;
  1618.     X{
  1619.     X    register ndptr p;
  1620.     X
  1621.     X    for (p = hashtab[hash(name)]; p != nil; p = p->nxtptr)
  1622.     X        if (strcmp(name, p->name) == 0)
  1623.     X            break;
  1624.     X    return (p);
  1625.     X}
  1626.     X
  1627.     X/*
  1628.     X * addent - hash and create an entry in the hash
  1629.     X *        table. The new entry is added in front
  1630.     X *        of a hash bucket.
  1631.     X */
  1632.     Xndptr addent(name)
  1633.     Xchar *name;
  1634.     X{
  1635.     X    register int h;
  1636.     X    ndptr p;
  1637.     X
  1638.     X    h = hash(name);
  1639.     X    if ((p = (ndptr) malloc(sizeof(struct ndblock))) != NULL) {
  1640.     X        p->nxtptr = hashtab[h];
  1641.     X        hashtab[h] = p;
  1642.     X        p->name = strsave(name);
  1643.     X    }
  1644.     X    else
  1645.     X        error("m4: no more memory.");
  1646.     X    return p;
  1647.     X}
  1648.     X
  1649.     X/*
  1650.     X * remhash - remove an entry from the hashtable
  1651.     X *
  1652.     X */
  1653.     Xremhash(name, all)
  1654.     Xchar *name;
  1655.     Xint all;
  1656.     X{
  1657.     X    register int h;
  1658.     X    register ndptr xp, tp, mp;
  1659.     X
  1660.     X    h = hash(name);
  1661.     X    mp = hashtab[h];
  1662.     X    tp = nil;
  1663.     X    while (mp != nil) {
  1664.     X        if (strcmp(mp->name, name) == 0) {
  1665.     X            mp = mp->nxtptr;
  1666.     X            if (tp == nil) {
  1667.     X                freent(hashtab[h]);
  1668.     X                hashtab[h] = mp;
  1669.     X            }
  1670.     X            else {
  1671.     X                xp = tp->nxtptr;
  1672.     X                tp->nxtptr = mp;
  1673.     X                freent(xp);
  1674.     X            }
  1675.     X            if (!all)
  1676.     X                break;
  1677.     X        }
  1678.     X        else {
  1679.     X            tp = mp;
  1680.     X            mp = mp->nxtptr;
  1681.     X        }
  1682.     X    }
  1683.     X}
  1684.     X
  1685.     X/*
  1686.     X * freent - free a hashtable information block
  1687.     X *
  1688.     X */
  1689.     Xfreent(p)
  1690.     Xndptr p;
  1691.     X{
  1692.     X    if (!(p->type & STATIC)) {
  1693.     X        free(p->name);
  1694.     X        if (p->defn != null)
  1695.     X            free(p->defn);
  1696.     X    }
  1697.     X    free(p);
  1698.     X}
  1699.     X
  1700. SHAR_EOF
  1701. if test 1617 -ne "`wc -c < 'look.c'`"
  1702. then
  1703.     echo shar: error transmitting "'look.c'" '(should have been 1617 characters)'
  1704. fi
  1705. fi # end of overwriting check
  1706. echo shar: extracting "'misc.c'" '(5005 characters)'
  1707. if test -f 'misc.c'
  1708. then
  1709.     echo shar: will not over-write existing file "'misc.c'"
  1710. else
  1711. sed 's/^    X//' << \SHAR_EOF > 'misc.c'
  1712.     X/*
  1713.     X * misc.c
  1714.     X * Facility: m4 macro processor
  1715.     X * by: oz
  1716.     X */
  1717.     X 
  1718.     X#include "mdef.h"
  1719.     X#include "extr.h" 
  1720.     X 
  1721.     Xextern char *malloc();
  1722.     X 
  1723.     X/*
  1724.     X * indx - find the index of second str in the
  1725.     X *        first str.
  1726.     X */
  1727.     Xindx(s1, s2)
  1728.     Xchar *s1;
  1729.     Xchar *s2;
  1730.     X{
  1731.     X        register char *t;
  1732.     X        register char *p;
  1733.     X        register char *m;
  1734.     X 
  1735.     X        for (p = s1; *p; p++) {
  1736.     X                for (t = p, m = s2; *m && *m == *t; m++, t++)
  1737.     X                        ;
  1738.     X                if (!*m)
  1739.     X                        return(p - s1);
  1740.     X        }
  1741.     X        return (-1);
  1742.     X}
  1743.     X 
  1744.     X/*
  1745.     X *  putback - push character back onto input
  1746.     X *
  1747.     X */
  1748.     Xputback (c)
  1749.     Xchar c;
  1750.     X{
  1751.     X        if (bp < endpbb)
  1752.     X                *bp++ = c;
  1753.     X        else
  1754.     X                error("m4: too many characters pushed back");
  1755.     X}
  1756.     X 
  1757.     X/*
  1758.     X *  pbstr - push string back onto input
  1759.     X *          putback is replicated to improve
  1760.     X *          performance.
  1761.     X *
  1762.     X */
  1763.     Xpbstr(s)
  1764.     Xregister char *s;
  1765.     X{
  1766.     X        register char *es;
  1767.     X    register char *zp;
  1768.     X
  1769.     X    es = s;
  1770.     X    zp = bp;
  1771.     X
  1772.     X        while (*es)
  1773.     X                es++;
  1774.     X        es--;
  1775.     X        while (es >= s)
  1776.     X                if (zp < endpbb)
  1777.     X                        *zp++ = *es--;
  1778.     X        if ((bp = zp) == endpbb)
  1779.     X                error("m4: too many characters pushed back");
  1780.     X}
  1781.     X 
  1782.     X/*
  1783.     X *  pbnum - convert number to string, push back on input.
  1784.     X *
  1785.     X */
  1786.     Xpbnum (n)
  1787.     Xint n;
  1788.     X{
  1789.     X        register int num;
  1790.     X 
  1791.     X        num = (n < 0) ? -n : n;
  1792.     X        do {
  1793.     X                putback(num % 10 + '0');
  1794.     X        }
  1795.     X        while ((num /= 10) > 0);
  1796.     X
  1797.     X        if (n < 0) putback('-');
  1798.     X}
  1799.     X 
  1800.     X/*
  1801.     X *  chrsave - put single char on string space
  1802.     X *
  1803.     X */
  1804.     Xchrsave (c)
  1805.     Xchar c;
  1806.     X{
  1807.     X/***        if (sp < 0)
  1808.     X                putc(c, active);
  1809.     X        else ***/ if (ep < endest)
  1810.     X                *ep++ = c;
  1811.     X        else
  1812.     X                error("m4: string space overflow");
  1813.     X}
  1814.     X 
  1815.     X/*
  1816.     X * getdiv - read in a diversion file, and
  1817.     X *          trash it.
  1818.     X */
  1819.     Xgetdiv(ind) {
  1820.     X        register int c;
  1821.     X        register FILE *dfil;
  1822.     X 
  1823.     X        if (active == outfile[ind])
  1824.     X                error("m4: undivert: diversion still active.");
  1825.     X        (void) fclose(outfile[ind]);
  1826.     X        outfile[ind] = NULL;
  1827.     X        m4temp[UNIQUE] = ind + '0';
  1828.     X        if ((dfil = fopen(m4temp, "r")) == NULL)
  1829.     X                error("m4: cannot undivert.");
  1830.     X        else
  1831.     X                while((c = getc(dfil)) != EOF)
  1832.     X                        putc(c, active);
  1833.     X        (void) fclose(dfil);
  1834.     X
  1835.     X#if vms
  1836.     X        if (remove(m4temp))
  1837.     X#else
  1838.     X    if (unlink(m4temp) == -1)
  1839.     X#endif
  1840.     X                error("m4: cannot unlink.");
  1841.     X}
  1842.     X 
  1843.     X/*
  1844.     X * Very fatal error. Close all files
  1845.     X * and die hard.
  1846.     X */
  1847.     Xerror(s)
  1848.     Xchar *s;
  1849.     X{
  1850.     X        killdiv();
  1851.     X        fprintf(stderr,"%s\n",s);
  1852.     X        exit(1);
  1853.     X}
  1854.     X 
  1855.     X/*
  1856.     X * Interrupt handling
  1857.     X */
  1858.     Xstatic char *msg = "\ninterrupted.";
  1859.     X 
  1860.     Xonintr() {
  1861.     X        error(msg);
  1862.     X}
  1863.     X 
  1864.     X/*
  1865.     X * killdiv - get rid of the diversion files
  1866.     X *
  1867.     X */
  1868.     Xkilldiv() {
  1869.     X        register int n;
  1870.     X 
  1871.     X        for (n = 0; n < MAXOUT; n++)
  1872.     X                if (outfile[n] != NULL) {
  1873.     X                        (void) fclose (outfile[n]);
  1874.     X                        m4temp[UNIQUE] = n + '0';
  1875.     X#if vms
  1876.     X            (void) remove (m4temp);
  1877.     X#else
  1878.     X                        (void) unlink (m4temp);
  1879.     X#endif
  1880.     X                }
  1881.     X}
  1882.     X 
  1883.     X/*
  1884.     X * save a string somewhere..
  1885.     X *
  1886.     X */
  1887.     Xchar *strsave(s)
  1888.     Xchar *s;
  1889.     X{
  1890.     X    register int n;
  1891.     X        char *p;
  1892.     X
  1893.     X        if ((p = malloc (n = strlen(s)+1)) != NULL)
  1894.     X                (void) memcpy(p, s, n);
  1895.     X        return (p);
  1896.     X}
  1897.     X 
  1898.     Xusage() {
  1899.     X        fprintf(stderr, "Usage: m4 [-Dname[=val]] [-Uname]\n");
  1900.     X        exit(1);
  1901.     X}
  1902.     X
  1903.     X#ifdef GETOPT
  1904.     X/*
  1905.     X * H. Spencer getopt - get option letter from argv
  1906.     X * 
  1907.     X *
  1908.     X#include <stdio.h>
  1909.     X *
  1910.     X */
  1911.     X
  1912.     Xchar    *optarg;    /* Global argument pointer. */
  1913.     Xint    optind = 0;    /* Global argv index. */
  1914.     X
  1915.     Xstatic char    *scan = NULL;    /* Private scan pointer. */
  1916.     X
  1917.     Xextern char    *index();
  1918.     X
  1919.     Xint
  1920.     Xgetopt(argc, argv, optstring)
  1921.     Xint argc;
  1922.     Xchar *argv[];
  1923.     Xchar *optstring;
  1924.     X{
  1925.     X    register char c;
  1926.     X    register char *place;
  1927.     X
  1928.     X    optarg = NULL;
  1929.     X
  1930.     X    if (scan == NULL || *scan == '\0') {
  1931.     X        if (optind == 0)
  1932.     X            optind++;
  1933.     X    
  1934.     X        if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
  1935.     X            return(EOF);
  1936.     X        if (strcmp(argv[optind], "--")==0) {
  1937.     X            optind++;
  1938.     X            return(EOF);
  1939.     X        }
  1940.     X    
  1941.     X        scan = argv[optind]+1;
  1942.     X        optind++;
  1943.     X    }
  1944.     X
  1945.     X    c = *scan++;
  1946.     X    place = index(optstring, c);
  1947.     X
  1948.     X    if (place == NULL || c == ':') {
  1949.     X        fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
  1950.     X        return('?');
  1951.     X    }
  1952.     X
  1953.     X    place++;
  1954.     X    if (*place == ':') {
  1955.     X        if (*scan != '\0') {
  1956.     X            optarg = scan;
  1957.     X            scan = NULL;
  1958.     X        } else {
  1959.     X            optarg = argv[optind];
  1960.     X            optind++;
  1961.     X        }
  1962.     X    }
  1963.     X
  1964.     X    return(c);
  1965.     X}
  1966.     X   
  1967.     X#endif
  1968.     X
  1969.     X#ifdef DUFFCP
  1970.     X/*
  1971.     X * This code uses Duff's Device (tm Tom Duff)
  1972.     X * to unroll the copying loop:
  1973.     X * while (count-- > 0)
  1974.     X *    *to++ = *from++;
  1975.     X */
  1976.     X
  1977.     X#define COPYBYTE     *to++ = *from++
  1978.     X
  1979.     Xmemcpy(to, from, count)
  1980.     Xregister char *from, *to;
  1981.     Xregister int count;
  1982.     X{
  1983.     X    if (count > 0) {
  1984.     X        register int loops = (count+8-1) >> 3;    /* div 8 round up */
  1985.     X
  1986.     X        switch (count&(8-1)) {            /* mod 8 */
  1987.     X        case 0: do {
  1988.     X            COPYBYTE;
  1989.     X        case 7:    COPYBYTE;
  1990.     X        case 6:    COPYBYTE;
  1991.     X        case 5:    COPYBYTE;
  1992.     X        case 4:    COPYBYTE;
  1993.     X        case 3:    COPYBYTE;
  1994.     X        case 2:    COPYBYTE;
  1995.     X        case 1:    COPYBYTE;
  1996.     X            } while (--loops > 0);
  1997.     X        }
  1998.     X
  1999.     X    }
  2000.     X}
  2001.     X
  2002.     X#endif
  2003. SHAR_EOF
  2004. if test 5005 -ne "`wc -c < 'misc.c'`"
  2005. then
  2006.     echo shar: error transmitting "'misc.c'" '(should have been 5005 characters)'
  2007. fi
  2008. fi # end of overwriting check
  2009. echo shar: extracting "'expr.c'" '(11531 characters)'
  2010. if test -f 'expr.c'
  2011. then
  2012.     echo shar: will not over-write existing file "'expr.c'"
  2013. else
  2014. sed 's/^    X//' << \SHAR_EOF > 'expr.c'
  2015.     X
  2016.     X/*
  2017.     X *      expression evaluator: performs a standard recursive
  2018.     X *      descent parse to evaluate any expression permissible
  2019.     X *      within the following grammar:
  2020.     X *
  2021.     X *      expr    :       query EOS
  2022.     X *      query   :       lor
  2023.     X *              |       lor "?" query ":" query
  2024.     X *      lor     :       land { "||" land }
  2025.     X *      land    :       bor { "&&" bor }
  2026.     X *      bor     :       bxor { "|" bxor }
  2027.     X *      bxor    :       band { "^" band }
  2028.     X *      band    :       eql { "&" eql }
  2029.     X *      eql     :       relat { eqrel relat }
  2030.     X *      relat   :       shift { rel shift }
  2031.     X *      shift   :       primary { shop primary }
  2032.     X *      primary :       term { addop term }
  2033.     X *      term    :       unary { mulop unary }
  2034.     X *      unary   :       factor
  2035.     X *              |       unop unary
  2036.     X *      factor  :       constant
  2037.     X *              |       "(" query ")"
  2038.     X *      constant:       num
  2039.     X *              |       "'" CHAR "'"
  2040.     X *      num     :       DIGIT
  2041.     X *              |       DIGIT num
  2042.     X *      shop    :       "<<"
  2043.     X *              |       ">>"
  2044.     X *      eqlrel  :       "="
  2045.     X *              |       "=="
  2046.     X *              |       "!="
  2047.     X *      rel     :       "<"
  2048.     X *              |       ">"
  2049.     X *              |       "<="
  2050.     X *              |       ">="
  2051.     X *
  2052.     X *
  2053.     X *      This expression evaluator is lifted from a public-domain
  2054.     X *      C Pre-Processor included with the DECUS C Compiler distribution.
  2055.     X *      It is hacked somewhat to be suitable for m4.
  2056.     X *
  2057.     X *      Originally by:  Mike Lutz
  2058.     X *                      Bob Harper
  2059.     X */
  2060.     X 
  2061.     X#define TRUE    1
  2062.     X#define FALSE   0
  2063.     X#define EOS     (char) 0
  2064.     X#define EQL     0
  2065.     X#define NEQ     1
  2066.     X#define LSS     2
  2067.     X#define LEQ     3
  2068.     X#define GTR     4
  2069.     X#define GEQ     5
  2070.     X#define OCTAL   8
  2071.     X#define DECIMAL 10
  2072.     X 
  2073.     Xstatic char *nxtch;     /* Parser scan pointer */
  2074.     X 
  2075.     X/*
  2076.     X * For longjmp
  2077.     X */
  2078.     X#include <setjmp.h>
  2079.     Xstatic jmp_buf  expjump;
  2080.     X 
  2081.     X/*
  2082.     X * macros:
  2083.     X *
  2084.     X *      ungetch - Put back the last character examined.
  2085.     X *      getch   - return the next character from expr string.
  2086.     X */
  2087.     X#define ungetch()       nxtch--
  2088.     X#define getch()         *nxtch++
  2089.     X 
  2090.     Xexpr(expbuf)
  2091.     Xchar *expbuf;
  2092.     X{
  2093.     X        register int rval;
  2094.     X 
  2095.     X        nxtch = expbuf;
  2096.     X        if (setjmp(expjump) != 0)
  2097.     X                return (FALSE);
  2098.     X        rval = query();
  2099.     X        if (skipws() == EOS)
  2100.     X                return(rval);
  2101.     X        experr("Ill-formed expression");
  2102.     X}
  2103.     X 
  2104.     X/*
  2105.     X * query : lor | lor '?' query ':' query
  2106.     X *
  2107.     X */
  2108.     Xquery()
  2109.     X{
  2110.     X        register int bool, true_val, false_val;
  2111.     X 
  2112.     X        bool = lor();
  2113.     X        if (skipws() != '?') {
  2114.     X                ungetch();
  2115.     X                return(bool);
  2116.     X        }
  2117.     X 
  2118.     X        true_val = query();
  2119.     X        if (skipws() != ':')
  2120.     X                experr("Bad query");
  2121.     X 
  2122.     X        false_val = query();
  2123.     X        return(bool ? true_val : false_val);
  2124.     X}
  2125.     X 
  2126.     X/*
  2127.     X * lor : land { '||' land }
  2128.     X *
  2129.     X */
  2130.     Xlor()
  2131.     X{
  2132.     X        register int c, vl, vr;
  2133.     X 
  2134.     X        vl = land();
  2135.     X        while ((c = skipws()) == '|' && getch() == '|') {
  2136.     X                vr = land();
  2137.     X                vl = vl || vr;
  2138.     X        }
  2139.     X 
  2140.     X        if (c == '|')
  2141.     X                ungetch();
  2142.     X        ungetch();
  2143.     X        return(vl);
  2144.     X}
  2145.     X 
  2146.     X/*
  2147.     X * land : bor { '&&' bor }
  2148.     X *
  2149.     X */
  2150.     Xland()
  2151.     X{
  2152.     X        register int c, vl, vr;
  2153.     X 
  2154.     X        vl = bor();
  2155.     X        while ((c = skipws()) == '&' && getch() == '&') {
  2156.     X                vr = bor();
  2157.     X                vl = vl && vr;
  2158.     X        }
  2159.     X 
  2160.     X        if (c == '&')
  2161.     X                ungetch();
  2162.     X        ungetch();
  2163.     X        return(vl);
  2164.     X}
  2165.     X 
  2166.     X/*
  2167.     X * bor : bxor { '|' bxor }
  2168.     X *
  2169.     X */
  2170.     Xbor()
  2171.     X{
  2172.     X        register int vl, vr, c;
  2173.     X 
  2174.     X        vl = bxor();
  2175.     X        while ((c = skipws()) == '|' && getch() != '|') {
  2176.     X                ungetch();
  2177.     X                vr = bxor();
  2178.     X                vl |= vr;
  2179.     X        }
  2180.     X 
  2181.     X        if (c == '|')
  2182.     X                ungetch();
  2183.     X        ungetch();
  2184.     X        return(vl);
  2185.     X}
  2186.     X 
  2187.     X/*
  2188.     X * bxor : band { '^' band }
  2189.     X *
  2190.     X */
  2191.     Xbxor()
  2192.     X{
  2193.     X        register int vl, vr;
  2194.     X 
  2195.     X        vl = band();
  2196.     X        while (skipws() == '^') {
  2197.     X                vr = band();
  2198.     X                vl ^= vr;
  2199.     X        }
  2200.     X 
  2201.     X        ungetch();
  2202.     X        return(vl);
  2203.     X}
  2204.     X 
  2205.     X/*
  2206.     X * band : eql { '&' eql }
  2207.     X *
  2208.     X */
  2209.     Xband()
  2210.     X{
  2211.     X        register int vl, vr, c;
  2212.     X 
  2213.     X        vl = eql();
  2214.     X        while ((c = skipws()) == '&' && getch() != '&') {
  2215.     X                ungetch();
  2216.     X                vr = eql();
  2217.     X                vl &= vr;
  2218.     X        }
  2219.     X 
  2220.     X        if (c == '&')
  2221.     X                ungetch();
  2222.     X        ungetch();
  2223.     X        return(vl);
  2224.     X}
  2225.     X 
  2226.     X/*
  2227.     X * eql : relat { eqrel relat }
  2228.     X *
  2229.     X */
  2230.     Xeql()
  2231.     X{
  2232.     X        register int vl, vr, rel;
  2233.     X 
  2234.     X        vl = relat();
  2235.     X        while ((rel = geteql()) != -1) {
  2236.     X                vr = relat();
  2237.     X 
  2238.     X                switch (rel) {
  2239.     X 
  2240.     X                case EQL:
  2241.     X                        vl = (vl == vr);
  2242.     X                        break;
  2243.     X                case NEQ:
  2244.     X                        vl = (vl != vr);
  2245.     X                        break;
  2246.     X                }
  2247.     X        }
  2248.     X        return(vl);
  2249.     X}
  2250.     X 
  2251.     X/*
  2252.     X * relat : shift { rel shift }
  2253.     X *
  2254.     X */
  2255.     Xrelat()
  2256.     X{
  2257.     X        register int vl, vr, rel;
  2258.     X 
  2259.     X        vl = shift();
  2260.     X        while ((rel = getrel()) != -1) {
  2261.     X 
  2262.     X                vr = shift();
  2263.     X                switch (rel) {
  2264.     X 
  2265.     X                case LEQ:
  2266.     X                        vl = (vl <= vr);
  2267.     X                        break;
  2268.     X                case LSS:
  2269.     X                        vl = (vl < vr);
  2270.     X                        break;
  2271.     X                case GTR:
  2272.     X                        vl = (vl > vr);
  2273.     X                        break;
  2274.     X                case GEQ:
  2275.     X                        vl = (vl >= vr);
  2276.     X                        break;
  2277.     X                }
  2278.     X        }
  2279.     X        return(vl);
  2280.     X}
  2281.     X 
  2282.     X/*
  2283.     X * shift : primary { shop primary }
  2284.     X *
  2285.     X */
  2286.     Xshift()
  2287.     X{
  2288.     X        register int vl, vr, c;
  2289.     X 
  2290.     X        vl = primary();
  2291.     X        while (((c = skipws()) == '<' || c == '>') && c == getch()) {
  2292.     X                vr = primary();
  2293.     X 
  2294.     X                if (c == '<')
  2295.     X                        vl <<= vr;
  2296.     X                else
  2297.     X                        vl >>= vr;
  2298.     X        }
  2299.     X 
  2300.     X        if (c == '<' || c == '>')
  2301.     X                ungetch();
  2302.     X        ungetch();
  2303.     X        return(vl);
  2304.     X}
  2305.     X 
  2306.     X/*
  2307.     X * primary : term { addop term }
  2308.     X *
  2309.     X */
  2310.     Xprimary()
  2311.     X{
  2312.     X        register int c, vl, vr;
  2313.     X 
  2314.     X        vl = term();
  2315.     X        while ((c = skipws()) == '+' || c == '-') {
  2316.     X                vr = term();
  2317.     X                if (c == '+')
  2318.     X                        vl += vr;
  2319.     X                else
  2320.     X                        vl -= vr;
  2321.     X        }
  2322.     X 
  2323.     X        ungetch();
  2324.     X        return(vl);
  2325.     X}
  2326.     X 
  2327.     X/*
  2328.     X * <term> := <unary> { <mulop> <unary> }
  2329.     X *
  2330.     X */
  2331.     Xterm()
  2332.     X{
  2333.     X        register int c, vl, vr;
  2334.     X 
  2335.     X        vl = unary();
  2336.     X        while ((c = skipws()) == '*' || c == '/' || c == '%') {
  2337.     X                vr = unary();
  2338.     X 
  2339.     X                switch (c) {
  2340.     X                case '*':
  2341.     X                        vl *= vr;
  2342.     X                        break;
  2343.     X                case '/':
  2344.     X                        vl /= vr;
  2345.     X                        break;
  2346.     X                case '%':
  2347.     X                        vl %= vr;
  2348.     X                        break;
  2349.     X                }
  2350.     X        }
  2351.     X        ungetch();
  2352.     X        return(vl);
  2353.     X}
  2354.     X 
  2355.     X/*
  2356.     X * unary : factor | unop unary
  2357.     X *
  2358.     X */
  2359.     Xunary()
  2360.     X{
  2361.     X        register int val, c;
  2362.     X 
  2363.     X        if ((c = skipws()) == '!' || c == '~' || c == '-') {
  2364.     X                val = unary();
  2365.     X 
  2366.     X                switch (c) {
  2367.     X                case '!':
  2368.     X                        return(! val);
  2369.     X                case '~':
  2370.     X                        return(~ val);
  2371.     X                case '-':
  2372.     X                        return(- val);
  2373.     X                }
  2374.     X        }
  2375.     X 
  2376.     X        ungetch();
  2377.     X        return(factor());
  2378.     X}
  2379.     X 
  2380.     X/*
  2381.     X * factor : constant | '(' query ')'
  2382.     X *
  2383.     X */
  2384.     Xfactor()
  2385.     X{
  2386.     X        register int val;
  2387.     X 
  2388.     X        if (skipws() == '(') {
  2389.     X                val = query();
  2390.     X                if (skipws() != ')')
  2391.     X                        experr("Bad factor");
  2392.     X                return(val);
  2393.     X        }
  2394.     X 
  2395.     X        ungetch();
  2396.     X        return(constant());
  2397.     X}
  2398.     X 
  2399.     X/*
  2400.     X * constant: num | 'char'
  2401.     X *
  2402.     X */
  2403.     Xconstant()
  2404.     X{
  2405.     X        /*
  2406.     X         * Note: constant() handles multi-byte constants
  2407.     X         */
  2408.     X 
  2409.     X        register int    i;
  2410.     X        register int    value;
  2411.     X        register char   c;
  2412.     X        int             v[sizeof (int)];
  2413.     X 
  2414.     X        if (skipws() != '\'') {
  2415.     X                ungetch();
  2416.     X                return(num());
  2417.     X        }
  2418.     X        for (i = 0; i < sizeof(int); i++) {
  2419.     X                if ((c = getch()) == '\'') {
  2420.     X                        ungetch();
  2421.     X                        break;
  2422.     X                }
  2423.     X                if (c == '\\') {
  2424.     X                        switch (c = getch()) {
  2425.     X                        case '0':
  2426.     X                        case '1':
  2427.     X                        case '2':
  2428.     X                        case '3':
  2429.     X                        case '4':
  2430.     X                        case '5':
  2431.     X                        case '6':
  2432.     X                        case '7':
  2433.     X                                ungetch();
  2434.     X                                c = num();
  2435.     X                                break;
  2436.     X                        case 'n':
  2437.     X                                c = 012;
  2438.     X                                break;
  2439.     X                        case 'r':
  2440.     X                                c = 015;
  2441.     X                                break;
  2442.     X                        case 't':
  2443.     X                                c = 011;
  2444.     X                                break;
  2445.     X                        case 'b':
  2446.     X                                c = 010;
  2447.     X                                break;
  2448.     X                        case 'f':
  2449.     X                                c = 014;
  2450.     X                                break;
  2451.     X                        }
  2452.     X                }
  2453.     X                v[i] = c;
  2454.     X        }
  2455.     X        if (i == 0 || getch() != '\'')
  2456.     X                experr("Illegal character constant");
  2457.     X        for (value = 0; --i >= 0;) {
  2458.     X                value <<= 8;
  2459.     X                value += v[i];
  2460.     X        }
  2461.     X        return(value);
  2462.     X}
  2463.     X 
  2464.     X/*
  2465.     X * num : digit | num digit
  2466.     X *
  2467.     X */
  2468.     Xnum()
  2469.     X{
  2470.     X        register int rval, c, base;
  2471.     X        int ndig;
  2472.     X 
  2473.     X        base = ((c = skipws()) == '0') ? OCTAL : DECIMAL;
  2474.     X        rval = 0;
  2475.     X        ndig = 0;
  2476.     X        while (c >= '0' && c <= (base == OCTAL ? '7' : '9')) {
  2477.     X                rval *= base;
  2478.     X                rval += (c - '0');
  2479.     X                c = getch();
  2480.     X                ndig++;
  2481.     X        }
  2482.     X        ungetch();
  2483.     X        if (ndig)
  2484.     X                return(rval);
  2485.     X        experr("Bad constant");
  2486.     X}
  2487.     X 
  2488.     X/*
  2489.     X * eqlrel : '=' | '==' | '!='
  2490.     X *
  2491.     X */
  2492.     Xgeteql()
  2493.     X{
  2494.     X        register int c1, c2;
  2495.     X 
  2496.     X        c1 = skipws();
  2497.     X        c2 = getch();
  2498.     X 
  2499.     X        switch (c1) {
  2500.     X 
  2501.     X        case '=':
  2502.     X                if (c2 != '=')
  2503.     X                        ungetch();
  2504.     X                return(EQL);
  2505.     X 
  2506.     X        case '!':
  2507.     X                if (c2 == '=')
  2508.     X                        return(NEQ);
  2509.     X                ungetch();
  2510.     X                ungetch();
  2511.     X                return(-1);
  2512.     X 
  2513.     X        default:
  2514.     X                ungetch();
  2515.     X                ungetch();
  2516.     X                return(-1);
  2517.     X        }
  2518.     X}
  2519.     X 
  2520.     X/*
  2521.     X * rel : '<' | '>' | '<=' | '>='
  2522.     X *
  2523.     X */
  2524.     Xgetrel()
  2525.     X{
  2526.     X        register int c1, c2;
  2527.     X 
  2528.     X        c1 = skipws();
  2529.     X        c2 = getch();
  2530.     X 
  2531.     X        switch (c1) {
  2532.     X 
  2533.     X        case '<':
  2534.     X                if (c2 == '=')
  2535.     X                        return(LEQ);
  2536.     X                ungetch();
  2537.     X                return(LSS);
  2538.     X 
  2539.     X        case '>':
  2540.     X                if (c2 == '=')
  2541.     X                        return(GEQ);
  2542.     X                ungetch();
  2543.     X                return(GTR);
  2544.     X 
  2545.     X        default:
  2546.     X                ungetch();
  2547.     X                ungetch();
  2548.     X                return(-1);
  2549.     X        }
  2550.     X}
  2551.     X 
  2552.     X/*
  2553.     X * Skip over any white space and return terminating char.
  2554.     X */
  2555.     Xskipws()
  2556.     X{
  2557.     X        register char c;
  2558.     X 
  2559.     X        while ((c = getch()) <= ' ' && c > EOS)
  2560.     X                ;
  2561.     X        return(c);
  2562.     X}
  2563.     X 
  2564.     X/*
  2565.     X * Error handler - resets environment to eval(), prints an error,
  2566.     X * and returns FALSE.
  2567.     X */
  2568.     Xexperr(msg)
  2569.     Xchar *msg;
  2570.     X{
  2571.     X        printf("mp: %s\n",msg);
  2572.     X        longjmp(expjump, -1);          /* Force eval() to return FALSE */
  2573.     X}
  2574. SHAR_EOF
  2575. if test 11531 -ne "`wc -c < 'expr.c'`"
  2576. then
  2577.     echo shar: error transmitting "'expr.c'" '(should have been 11531 characters)'
  2578. fi
  2579. fi # end of overwriting check
  2580. #    End of shell archive
  2581. exit 0
  2582.